
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libavdevice/avdevice.h>
#include <libavformat/version.h>
#include <libavutil/time.h>
#include <libavutil/mathematics.h>
#include <libavfilter/buffersink.h>
#include <libavfilter/buffersrc.h>
#include <libavutil/avutil.h>
#include <libavutil/imgutils.h>
#include <libavutil/pixfmt.h>
#include <libswresample/swresample.h>

#pragma comment(lib, "avcodec.lib")
#pragma comment(lib, "avdevice.lib")
#pragma comment(lib, "avfilter.lib")
#pragma comment(lib, "avformat.lib")
#pragma comment(lib, "avutil.lib")
#pragma comment(lib, "postproc.lib")
#pragma comment(lib, "swresample.lib")
#pragma comment(lib, "swscale.lib")
}

#include <thread>
#include <mutex>
#include <list>
#include <functional>
#include <memory>
#include <string>

#pragma warning (disable:4996)

using FuncIStImageCb = std::function<void(void*, int&, int&, int&)>;

class FFMpeger
{
public:
	FFMpeger();
	~FFMpeger();
	void init();
	void openInput(const char* inputPath);
	int initEncoder(int w, int h, AVCodecID codecID = AV_CODEC_ID_H264);
	int initMuxer(const char* outputPath, const char* fmt);
	int doSWS(unsigned char* src_buf, int src_w, int src_h, AVPixelFormat src_pixfmt,
				unsigned char* dst_buf, int dst_w, int dst_h, AVPixelFormat dst_pixfmt,
				int rescale_method = SWS_BICUBIC);

	void yuv2h264(unsigned char* src, int src_w, int src_h, AVPixelFormat src_pixfmt,
		int dst_w, int dst_h, AVPixelFormat dst_pixfmt = AV_PIX_FMT_YUV420P, bool bNewThread = false);

	void encoding(AVFrame* frame);
	void testH264(unsigned char* src, int src_w, int src_h, AVPixelFormat src_pixfmt,
		int dst_w, int dst_h, AVPixelFormat dst_pixfmt = AV_PIX_FMT_YUV420P);

    static void encodeFrame(void* args);
	void handleEncodeFrame();


public:
	AVFormatContext* m_pInFmtCtx;
	int m_nVideoIndex;
	
	AVFrame* yuvframe;
	AVPacket pack;

	AVCodecContext* codec_ctx;
	AVFormatContext* fmt_ctx;
	const AVOutputFormat* ofmt;
	AVStream* outStream;
	const AVCodec* codec;


	std::thread* m_pEncodeThread;
	std::mutex m_objEncodeMtx;

	std::mutex m_pushFrameMtx;
	std::list <AVFrame*> m_vFrameList;

	SwsContext* sws_ctx;
	uint8_t* src_data[4];
	int src_linesize[4];

	uint8_t* dst_data[4];
	int dst_linesize[4];
	unsigned char* picture_buf;

	bool m_bIsEncoderInited;
	bool m_bIsMuxerInited;

	bool m_bRunning;
	bool m_bFirstFrame;
	int64_t start_time;
};

